package com.fast.admin.common.shiro;

import com.fast.admin.common.utils.CipherUtil;
import com.fast.admin.common.utils.Const;
import com.fast.admin.common.utils.ShiroUtil;
import com.fast.admin.entity.sys.Role;
import com.fast.admin.entity.sys.User;
import com.fast.admin.service.sys.IRoleService;
import com.fast.admin.service.sys.IUserService;
import com.fast.common.util.CommonUtil;
import com.fast.common.util.SpringWebContextUtil;
import com.fast.common.util.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 作者：ykc
 * 描述：自定义权限匹配和账号密码匹配
 * 时间：2018年04月17日10:41:29
 */
@Slf4j
@Component
public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    private SessionDAO sessionDAO;

    /**
     * 权限认证
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
            doClearCache(principals);
            SecurityUtils.getSubject().logout();
            return null;
        }
       String currentUsername = (String) super.getAvailablePrincipal(principals);
        IUserService userService = (IUserService) SpringWebContextUtil.getApplicationContext().getBean("userService");
        IRoleService roleService = (IRoleService) SpringWebContextUtil.getApplicationContext().getBean("roleService");
        User user = userService.findByUsername(currentUsername);
        if (user != null) {
            List<Role> roles = roleService.selectByUserId(user.getId());
            if (!CommonUtil.properIsNULL(roles)){
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                // 添加角色
                for (Role role : roles) {
                    info.addRole(role.getCode());
                }
                return info;
            }
        } else {
            throw new AuthorizationException();
        }
        return null;
    }

    /***
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        AuthenticationInfo authenticationInfo = null;
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());
        IUserService userService = (IUserService) SpringWebContextUtil.getApplicationContext().getBean("userService");
        User user = userService.findByUsername(username);
        if (user != null) {
            String pwdEncrypt = CipherUtil.createPwdEncrypt(username, CipherUtil.generatePassword(password), user.getSalt());
            if (user.getPassword().equals(pwdEncrypt)) {
                clearUserSession(user.getId(), ShiroUtil.getSession());
                IRoleService roleService = (IRoleService) SpringWebContextUtil.getApplicationContext().getBean("roleService");
                ShiroUtil.setSession(Const.SYSTEM_USER, user);
                ShiroUtil.setSession(Const.SYSTEM_ROLE, roleService.selectByUserId(user.getId()));
                authenticationInfo = new SimpleAuthenticationInfo(username, password, getName());
                return authenticationInfo;
            } else {
                log.error("密码错误");
                throw new IncorrectCredentialsException();
            }
        } else {
            log.error("账号不存在");
            throw new UnknownAccountException();
        }
    }

    /**
     * 踢掉用户下线
     *
     * @param pk
     * @param current
     */
    public void clearUserSession(Serializable pk, Session current) {
        ThreadPoolUtil.INSTANCE.getCachedThreadPool(() -> {
            Collection<Session> sessionCollection = sessionDAO.getActiveSessions();
            for (Session session : sessionCollection) {
                //当前遍历到的session和当前用户的session一致,则不管
                if (session.getId().equals(current.getId())) {
                    continue;
                }
                User user = (User) session.getAttribute(Const.SYSTEM_USER);
                if (user != null && pk.equals(user.getId())) {
                    session.setTimeout(0);
                    // 设置session立即失效，即将其踢出系统
                    sessionDAO.delete(session);
                    clearCache();
                }
            }
        });
    }

    protected void clearCache() {
        PrincipalCollection principals = SecurityUtils.getSubject()
                .getPrincipals();
        super.clearCache(principals);
    }
}
